﻿
#ifndef  MAT44_H
#define MAT44_H

#include <string>

// 顶点，只有4个元素，相当于1行4列的矩阵  [ x   y  	z	w ]
struct  VERTEX4
{
	VERTEX4(float xVal, float yVal, float zVal, float wVal=1.0)
	{
		x = xVal;
		y = yVal;
		z = zVal;
		w = wVal;
	}

	VERTEX4()  { x = 0.0;   y = 0.0;  z = 0.0;  w = 1.0; }

	void setValue(float xVal, float yVal, float zVal, float wVal) 
	{
		x = xVal;
		y = yVal;
		z = zVal;
		w = wVal;
	}

	float x;
	float y;
	float z;
	float w;
};

struct RECT_VERTEX4  // 二维平面的矩形，以 VERTEX 为作内部参数
{
	VERTEX4  lb;    // 左下角
	VERTEX4  rb;	// 右下角
	VERTEX4  rt;	// 右上角
	VERTEX4  lt;		// 左上角
};

// 4*4的变换矩阵
class Mat44
{
public:
	
	enum
	{
		Mat44_ERR_NO = 0,							// 无错误
		Mat44_ERR_param_is_null = 10,		// 形参是空值
		Mat44_ERR_index_over = 20,			// 下标越界
	};

	enum
	{
		ELEMENT_COUNT = 16,		// 元素总数量
		ROW_COUNT = 4,				// 行的总数量
		COL_COUNT = 4,					// 列的总数量
	};

	Mat44();
	~Mat44();

	// 设置所有的元素值
	int setAllElement(float fVal[16], int iCount);

	/* --------------------------------------------------------------------------
	函数说明：设置元素值，用一维数组 16 个下标的方式
	传入参数：
		iIndex		下标值
		fVal			矩阵元素值
	返回值：
		成功则返回 0，失败返回错误码
	-------------------------------------------------------------------------- */
	int setElement16(int iIndex, float fVal);

	/* --------------------------------------------------------------------------
	函数说明：获得元素值，用一维数组 16 个下标的方式
	传入参数：
	    iIndex		下标值
	传出参数
	    fVal			矩阵元素值
	返回值：
		成功则返回 0，失败返回错误码
	-------------------------------------------------------------------------- */
	int getElement16(int iIndex, float& fVal) const;

	/* --------------------------------------------------------------------------
	函数说明：设置元素值，用二维数组 4*4 个下标的方式
	传入参数：
		iRow	第几行
		iCol		第几列
		fVal		矩阵元素值
	返回值：
		成功则返回 0，失败返回错误码
	-------------------------------------------------------------------------- */
	int setElement44(int iRow, int iCol, float fVal);

	/* --------------------------------------------------------------------------
	函数说明：设置元素值，用二维数组 4*4 个下标的方式
	传入参数：
		iRow	第几行
		iCol		第几列
	传出参数
		fVal			矩阵元素值
	返回值：
		成功则返回 0，失败返回错误码
	-------------------------------------------------------------------------- */
	int getElement44(int iRow, int iCol, float& fVal) const;
	
	/* 设置为4阶 E 矩阵，即如下矩阵
	1.0f, 0.0f, 0.0f, 0.0f,
	0.0f, 1.0f, 0.0f, 0.0f,
	0.0f, 0.0f, 1.0f, 0.0f,
	0.0f, 0.0f, 0.0f, 1.0f
	*/
	void setIdentity();

	/* 设置为4阶 O 矩阵，即如下矩阵
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0
	*/
	void setZero();

	/* --------------------------------------------------------------------------
	函数说明：根据移动的距离建立移动矩阵
	传入参数：
		xTranslation   x轴的移动距离
		yTranslation	y轴的移动距离
		zTranslation	z轴的移动距离
	传出参数：
		dst	移动矩阵
	-------------------------------------------------------------------------- */
	static void createTranslation(float xTranslation, float yTranslation, float zTranslation, Mat44& dst);

	/* --------------------------------------------------------------------------
	函数说明：根据绕Z轴旋转的角度建立绕Z轴旋转的矩阵
	传入参数：
		angle   绕Z轴旋转的角度，是  360度的那种角度
	传出参数：
		dst	绕Z轴旋转的矩阵
	-------------------------------------------------------------------------- */
	static void createRotationZ(float angle, Mat44& dst);

	/* --------------------------------------------------------------------------
	函数说明：矩阵相乘，即 a * b = c
	传入参数：
		aIn			左边的矩阵
		bIn			右边的矩阵
	传出参数
		c			相乘后的矩阵
	返回值：
		成功则返回 0，失败返回错误码
	-------------------------------------------------------------------------- */
	static int multiplication(const Mat44* aIn, const Mat44* bIn, Mat44* cOut);

	/* --------------------------------------------------------------------------
	函数说明：顶点乘矩阵，即 aIn * bIn = c ， 因为 cocos2d 的公式为： 顶点0 * 变换矩阵 = 顶点1
	传入参数：
		aIn			左边的顶点
		bIn			右边的矩阵
	传出参数
		c			相乘后的顶点
	返回值：
		成功则返回 0，失败返回错误码
	-------------------------------------------------------------------------- */
	static int vertexMultipyMat(const VERTEX4* aIn, const Mat44* bIn, VERTEX4* c);

	/* --------------------------------------------------------------------------
	函数说明：根据角度值获得弧度值
	传入参数：
		angle   角度，是  360度的那种角度
	返回值：
		弧度值
	-------------------------------------------------------------------------- */
	static float angleToRadian(float angle);

	/* --------------------------------------------------------------------------
	函数说明：根据弧度值获得角度值
	传入参数：
		radian   弧度值，是 PI 那种度
	返回值：
		角度值
	-------------------------------------------------------------------------- */
	static float radianToAngle(float radian);

	//int Test();
	int Test()	{ return 125; }
private:

	/* --------------------------------------------------------------------------
	函数说明：获得 a 矩阵第 iRow 行与 b 矩阵第  iCol 列相乘的结果值
	                  此函数是为两个矩阵相乘作配套的。
	传入参数：
		a							左边的矩阵
		aRowIndex		a矩阵第几行
		b							右边的矩阵
		bColNoIndex	b矩阵第几例
	传出参数：
		ce	相乘后的值
	返回值：
		成功则返回 0，失败返回错误码
	-------------------------------------------------------------------------- */
	static int get_MatARow_MatBCol_Multi(const Mat44* a, int aRowIndex, const Mat44* b, int bColNoIndex, float& ce);

private:
	/* --------------------------------------------------------------------------
	函数说明：矩阵乘顶点，即 a * b = c 
	                   注意：此函数在 cocos2d 的矩阵变换里面用不到，因为 cocos2d 的公式为： 顶点0 * 变换矩阵 = 顶点1
	传入参数：
		aIn			左边的矩阵
		bIn			右边的顶点
	传出参数
		c			相乘后的顶点
	返回值：
		成功则返回 0，失败返回错误码
	-------------------------------------------------------------------------- */
	static int matMultipyVertex(const Mat44* aIn, const VERTEX4* bIn, VERTEX4* c);

public:
	static float PI;	// 圆周率

private:
	float		e[ROW_COUNT][COL_COUNT];    // 所有的元素
	float*		pe;			// 指向 e 的指针，方便进行  e[16] 的操作
};

#endif